/*
 * jquery.juice.crop.js
 *
 * Juice Library Crop v0.1.0
 * Date: 2009-09-01
 * Requires: jQuery v1.3 or later
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Copyright 2009 Steve Whiteley (http://jui.ce.it)
 */

(function($) {
	$.fn.crop = function(callerSettings) {
		var settings = $.extend(true, {}, $.fn.crop.settings, callerSettings);
		return this.each(function() {
			var n = $(this), mask = {}, corners, area, origin, w, h, mouse, corner;
			var setup = function() {
				if (n.parent().hasClass(settings.plugin)) {
					return;
				}
				n.addClass(settings.plugin+'-img')
					.attr('galleryimg', 'no')
					.wrap($('<div />')
					.css({
						position: 'relative',
						height: h,
						width: w,
						display: ($.support.cssFloat ? 'inline-block' : 'inline'),
						overflow: 'hidden'
					}).addClass(settings.plugin))
					.parent()
					.addClass(settings.plugin+(settings.fixed == true ? '-fixed' : '-resize'))
					.mousedown(pickup);
				$.each(['top', 'right', 'bottom', 'left'], function(i, name) {
					mask[name] = $('<div />').css({
						position: 'absolute',
						opacity: settings.opacity,
						top: 0,
						left: 0,
						fontSize: 0,
						lineHeight: 0,
						overflow: 'hidden'
					})
					.addClass(settings.plugin+'-mask')
					.insertAfter(n);
					if (mask[name].css('background-color') == 'transparent') {
						mask[name].css('background-color', settings.mask);
					}
				});
				if (settings.width < settings.minWidth) {
					settings.minWidth = settings.width;
				}
				if (settings.height < settings.minHeight) {
					settings.minHeight = settings.height;
				}
				if (settings.fixed == false) {
					var min = 0;
					corners = {};
					$.each(['nw', 'ne', 'se', 'sw'], function(i, name) {
						corners[name] = $('<div />')
							.css({
								position: 'absolute',
								top: 0,
								left: 0,
								width: settings.corner.size,
								height: settings.corner.size,
								opacity: settings.corner.opacity,
								cursor: name+'-resize',
								fontSize: 0,
								lineHeight: 0
							})
							.data('name', name)
							.insertAfter(n)
							.addClass(settings.plugin+'-corner')
							.addClass(settings.plugin+'-corner-'+name)
							.mousedown(pickup);
						if (corners[name].css('background-color') == 'transparent') {
							corners[name].css('background-color', settings.corner.color);
						}					
					});
					min = (corners['nw'].outerWidth() * 2) + 1;
					if (settings.minWidth < min) {
						settings.minWidth = min;
					}
					if (settings.minHeight < min) {
						settings.minHeight = min;
					}
				}
				enable();
			};
			var enable = function() {
				w = n.width(), h = n.height();
				$.each(mask, function(name) {
					switch (name) {
						case 'top':
							$(this).css({
								height: 50,
								width: w
							});
						break;
						case 'right':
							$(this).css({
								width: 100,
								height: 100
							});
						break;
						case 'bottom':
							$(this).css({
								height: 50,
								width: w
							});
						break;
						case 'left': 
							$(this).css({
								width: 100,
								height: 100
							});
						break;
					}
				});
				if (settings.ratio) {
					settings.maxWidth = settings.maxHeight = Math.max(
						settings.maxWidth,
						settings.maxHeight
					);
					settings.minWidth = settings.minHeight = Math.max(
						settings.minWidth,
						settings.minHeight
					);
				}
				if (!settings.maxWidth || settings.maxWidth > w) {
					settings.maxWidth = w;
				} else if (settings.width > settings.maxWidth) {
					settings.width = settings.maxWidth;
				}
				if (!settings.maxHeight || settings.maxHeight > h) {
					settings.maxHeight = h;
				} else if (settings.height > settings.maxHeight) {
					settings.height = settings.maxHeight;
				}
				area = {
					w: settings.width > w ? settings.maxWidth : settings.width,
					h: settings.height > h ? settings.maxHeight : settings.height,
					x: settings.offsetX !== false ? Math.abs(settings.offsetX) : (w - settings.width) / 2,
					y: settings.offsetY !== false ? Math.abs(settings.offsetY) : (h - settings.height) / 2
				};
				position();
			};
			var position = function() {
				dimensions();
				mask.top
					.height(area.y);
				mask.right
					.css({
						top: area.y,
						left: area.x + area.w,
						height: area.h,
						width: w - (area.x + area.w)
					});
				mask.bottom
					.css({
						top: area.h + area.y,
						height: h - (area.h + area.y)
					});
				mask.left
					.css({
						top: area.y,
						height: area.h,
						width: area.x
					});
				if (settings.fixed == false) {
					$.each(corners, function(name) {
						switch (name) {
							case 'nw':
								$(this).css({
									left: area.x,
									top: area.y
								});
							break;
							case 'ne':
								$(this).css({
									left: (area.x + area.w) - $(this).outerWidth(),
									top: area.y
								});
							break;
							case 'se':
								$(this).css({
									left: (area.x + area.w) - $(this).outerWidth(),
									top: (area.y + area.h) - $(this).outerHeight()
								});
							break;
							case 'sw':
								$(this).css({
									left: area.x,
									top: (area.y + area.h) - $(this).outerHeight()
								});
							break;
						}
					});
				}
				if ($.isFunction(settings.onDrag)) {
					settings.onDrag({
						x: area.x,
						y: area.y,
						width: area.w,
						height: area.h
					}, n);
				}
			};
			var dimensions = function() {
				if (area.x < 0) {
					area.x = 0;
				} else if (area.x > w - area.w) {
					area.x = w - area.w;
				}
				if (area.y < 0) {
					area.y = 0;
				} else if (area.y > h - area.h) {
					area.y = h - area.h;
				}
			};
			var pickup = function(e) {
				if ($(e.target).hasClass(settings.plugin+'-corner')) {
					corner = $(e.target)
						.css('opacity', settings.corner.opacity + .2)
						.addClass(settings.plugin+'-corner-active');
				} else {
					n.parent().css('cursor', 'move');
				}
				origin = $.extend({}, area, {
					ratio: (area.w > area.h ? (area.w / area.h) : (area.h / area.w))
				});	
				e.preventDefault();
				var o = n.offset();
				mouse = {
					x: (e.pageX - o.left) - area.x,
					y: (e.pageY - o.top) - area.y,
					offset: {
						y: (area.y + area.h) - (e.pageY - o.top),
						x: (area.x + area.w) - (e.pageX - o.left)
					}
				};
				$.each(mask, function() {
					$(this).css('opacity', settings.opacity + .2);
				});
				$(document).mousemove(move)
					.mouseup(drop);
				if ($.isFunction(settings.onDrag)) {
					settings.onDrag(area, n);
				}
			};
			var move = function(e) {
				e.preventDefault()
				var o = $(n).offset();
				if (corner) {
					var offset = corner.offset();
					var view = {
						x: Math.max(0, (e.pageX - o.left) - mouse.x),
						y: Math.max(0, (e.pageY - o.top) - mouse.y)
					};
					switch (corner.data('name')) {
						case 'nw':
							area.x = view.x;
							area.y = view.y;
							area.w = w - mask.right.width() - (area.x > 0 ? area.x : 0);
							area.h = h - mask.bottom.height() - (area.y > 0 ? area.y : 0);
						break;
						case 'ne':
							area.y = view.y;
							area.h = h - mask.bottom.height() - (area.y > 0 ? area.y : 0);
							area.w = ((e.pageX - o.left) - area.x) + mouse.offset.x;
						break;
						case 'se':
							area.w = ((e.pageX - o.left) - area.x) + mouse.offset.x;
							area.h = ((e.pageY - o.top) - area.y) + mouse.offset.y;
						break;
						case 'sw':
							area.x = view.x;
							area.w = w - mask.right.width() - (area.x > 0 ? area.x : 0);
							area.h = ((e.pageY - o.top) - area.y) + mouse.offset.y;
						break;
					}		
					if (area.h + area.y > h) {
						area.h = h - area.y;
					} 
					if (area.h < settings.minHeight) {
						area.h = settings.minHeight;
						if ($.inArray(corner.data('name'), ['nw', 'ne']) != -1) {
							area.y = h - mask.bottom.height() - settings.minHeight;
						}
					} else if (settings.maxHeight && area.h > settings.maxHeight) {
						area.h = settings.maxHeight;
						if ($.inArray(corner.data('name'), ['nw', 'ne']) != -1) {
							area.y = h - mask.bottom.height() - settings.maxHeight;
						}
					}
					if (area.w + area.x > w) {
						area.w = w - area.x;
					}
					if (area.w < settings.minWidth) {
						area.w = settings.minWidth;
						if ($.inArray(corner.data('name'), ['nw', 'sw']) != -1) {
							area.x = w - mask.right.width() - settings.minWidth;
						}
					} else if (settings.maxWidth && area.w > settings.maxWidth) {
						area.w = settings.maxWidth;
						if ($.inArray(corner.data('name'), ['nw', 'sw']) != -1) {
							area.x = w - mask.right.width() - settings.maxWidth;
						}
					}
					if (settings.ratio) {
						var resize = Math.max(
							Math.max(settings.minWidth, settings.minHeight),
							Math.min(
								area.w,
								area.h,
								Math.max(settings.maxWidth, settings.maxHeight)
							)
						);
						var size = {};
						if (settings.width < settings.height) {
							size.h = (resize * origin.ratio);
							size.w = resize;
							if (size.h + area.y > h) { 
								size.h = Math.max(h - area.y, settings.minWidth + size.h / origin.ratio);
								size.w = Math.max(Math.round(size.h / origin.ratio), settings.minWidth);
							}
						} else if (settings.width > settings.height) {
							size.h = resize;
							size.w = (resize * origin.ratio);
							if (size.w + area.x > w) {
								size.w = Math.max(w - area.x, settings.minHeight + size.w / origin.ratio);
								size.h = Math.max(Math.round(size.w / origin.ratio), settings.minHeight);
							}
						} else {
							size.w = size.h = resize;
						}
						switch (corner.data('name')) {
							case 'nw':								
								area.x += (area.w - size.w);
								area.y += (area.h - size.h);
							break;
							case 'ne':
								area.y += (area.h - size.h);
							break;
							case 'sw':
								area.x += (area.w - size.w);
							break;
						}
						area.h = size.h;
						area.w = size.w;
					}
				} else {
					$.extend(area, {
						x: (e.pageX - o.left) - mouse.x,
						y: (e.pageY - o.top) - mouse.y
					});	
				}			
				position();
			};
			var drop = function() {
				if (corner) {
					corner.css('opacity', settings.corner.opacity)
						.removeClass(settings.plugin+'-corner-active');
					corner = false;
				}
				$(document).unbind('mousemove')
					.unbind('mouseup');
				if ($.isFunction(settings.onDrop)) {
					settings.onDrop(n);
				}
				$.each(mask, function() {
					$(this).css('opacity', settings.opacity);
				});
				n.parent().css('cursor', 'auto');
			};
			setup();
		});
	};
	$.fn.crop.settings = {
		corner: {
			size: 10,
			color: 'white',
			opacity: 0.5
		},
		fixed: false,
		height: 150,
		mask: 'black',
		maxHeight: false,
		maxWidth: false,
		minHeight: false,
		minWidth: false,
		offsetX: false,
		offsetY: false,
		onPickup: false,
		onDrag: false,
		onDrop: false,
		opacity: 0.5,
		plugin: 'juice-crop',
		ratio: false,
		width: 150
	};
})(jQuery);